package com.codeyang.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.codeyang.es.ProdEs;
import com.codeyang.service.SearchService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.AbstractQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 描述:
 *
 * @author CodeYang_Site
 * @version 2021/5/29 15:47
 */

@Slf4j
@Service
public class SearchServiceImpl implements SearchService {


    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;


    /**
     * 根据标签id 分组商品信息
     *
     * @param tagId
     * @param size
     * @param current
     * @return
     */
    @Override
    public Page<ProdEs> getProdByTags(Long tagId, Integer size, Integer current) {
        TermQueryBuilder termQuery = QueryBuilders.termQuery("tagList", tagId);
        return query(termQuery, size, current, null);
    }

    /**
     * 根据关键字查询商品信息同时根据策略排序
     *
     * @param prodName
     * @param size
     * @param current
     * @param sort
     * @return
     */
    @Override
    public Page<ProdEs> getProdByProdName(String prodName, Integer size, Integer current, Integer sort) {
        MatchQueryBuilder matchQueryBuilder = null;
        if (StringUtils.hasText(prodName)) {
            matchQueryBuilder = QueryBuilders.matchQuery("prodName", prodName);
        }
        return query(matchQueryBuilder, size, current, sort);
    }

    /**
     * 根据分类id查询商品
     * 查询类型 字段值查询
     *
     * @param categoryId
     * @param size
     * @param current
     * @return
     */
    @Override
    public Page<ProdEs> getProdByCategoryId(Long categoryId, Integer size, Integer current) {

        TermQueryBuilder termQuery = QueryBuilders.termQuery("categoryId", categoryId);
        return query(termQuery, size, current, null);
    }


    /**
     * 封装真正的查询操作
     * 暂时放弃:
     * 封装的真正查询操作,因为有根据字段值查询|全查询|根据关键字段查询,这样可以写一套通用的操作
     * 1.到这里肯定有分页
     * 2.不一定有高亮
     * 3.不一定有排序
     *
     * @param queryBuilder
     * @param size
     * @param current
     * @param sort
     * @return
     */
    private Page<ProdEs> query(AbstractQueryBuilder queryBuilder, Integer size, Integer current, Integer sort) {
        Page<ProdEs> prodEsPage = new Page<>(current, size);
        //1. 分页和排序都是通用的
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withPageable(PageRequest.of(current - 1, size));
        //2. 判断排序
        if (ObjectUtils.isEmpty(sort)) {
            sort = 1;
        }
        //3. 专门处理排序的
        SortBuilder sortBuilder = prodSort(sort);
        //4.分页
        nativeSearchQueryBuilder.withSort(sortBuilder);
        //5.组装条件 可以是任意的 tear 专门 math 匹配 等.....
        nativeSearchQueryBuilder.withQuery(queryBuilder);
        //6 高亮
        // 高亮
        if (null != queryBuilder && queryBuilder.getClass().equals(MatchQueryBuilder.class)) {

            HighlightBuilder.Field field = new HighlightBuilder.Field("prodName");
            field.preTags("<font style='color:red'><strong>");
            field.postTags("</strong></font>");
            // 组装高亮
            nativeSearchQueryBuilder.withHighlightFields(field);
        }
        // 查询
        SearchHits<ProdEs> searchHits = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), ProdEs.class);
        ArrayList<ProdEs> prodEsArrayList = new ArrayList<>();
        // 处理高亮内容
        searchHits.forEach(searchHit -> {
            ProdEs prodEs = searchHit.getContent();
            List<String> prodNameHighs = searchHit.getHighlightField("prodName");
            if (!CollectionUtils.isEmpty(prodNameHighs)) {
                String highName = prodNameHighs.get(0);
                if (StringUtils.hasText(highName)) {
                    prodEs.setProdName(highName);
                }
            }
            prodEsArrayList.add(prodEs);
        });
        prodEsPage.setRecords(prodEsArrayList);
        prodEsPage.setTotal(searchHits.getTotalHits());
        return prodEsPage;
    }


    /**
     * 排序的处理
     *
     * @param sort
     * @return
     */
    private SortBuilder prodSort(Integer sort) {

        switch (sort) {
            case 0:
                // 综合  好评 倒排
                return SortBuilders.fieldSort("positiveRating").order(SortOrder.DESC);
            case 1:
                // 销量
                return SortBuilders.fieldSort("soldNum").order(SortOrder.DESC);
            case 2:
                // 价格
                return SortBuilders.fieldSort("price").order(SortOrder.ASC);
            default:
                // 库存
                return SortBuilders.fieldSort("totalStocks").order(SortOrder.DESC);

        }

    }


}
